/*
 * Copyright (c) 2019-2029, ZeusOS Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author            Notes
 * 2021-03-23     longmain       first version
 */


#ifndef __ZOS_FLASH_H__
#define __ZOS_FLASH_H__
#include "zos_def.h"

/**
 * @brief  FLASH操作块大小，每次需要操作4K
 */
#define  ZOS_FLASH_SECTOR_LENGTH                       (0x1000)        //0x1000	4096Byte

//用户可用NV的FLASH操作首地址。
#define  ZOS_FLASH_USER_NV_BASE                         0x271FC000

//用户可用NV的FLASH最大长度。
#define  ZOS_FLASH_USER_NV_LEN_MAX                      0x4000 //NV掉电存储共16K

/**
 * @brief  使用骑士的FTL磨损算法机制，用户可用的有效空间，需要去除头尾保护字段
 */
#define  ZOS_FLASH_FTL_AVAILABLE_SIZE                   (ZOS_FLASH_SECTOR_LENGTH-4-16) // 0x1000-4-16

/**
 * @brief 读取FLASH中存储的数据。一个扇区4K字节耗时183us
 * 
 * @param addr     [IN] FLASH中存储数据的地址。
 * @param data     [IN] 读取数据的地址，首次读取前需要先擦除。
 * @param size     [IN] 读取数据的长度.
 */
void zos_flash_read(zos_uint32_t addr, void *data, zos_uint32_t size);

/**
 * @brief  擦除并将新数据写入FLASH。 一个扇区4K字节耗时54ms
 * 
 * @param addr     [IN] FLASH中存储数据的地址。
 * @param data     [IN] 要写入FLASH数据的首地址。必须4K字节对齐
 * @param size     [IN] 写入数据的长度.
 * 
 * @attention      由于异常断电会造成flash内容损坏，所以客户必须自行添加头尾校验位来确保内容的有效性。 
 * @warning        该接口会执行擦除和写入两个动作，对于非整个扇区写入的场景，建议客户统一先执行zos_flash_erase，再多次调用zos_flash_write_no_erase接口，以降低坏块风险！
 * 
 * @return ZOS_EOK: 写入成功  ZOS_ELowVbat: 模组电压过低，禁止写入flash
 */
zos_err_t zos_flash_write(zos_uint32_t addr,void *data, zos_uint32_t size);

/**
 * @brief   将新数据写入FLASH而不擦除。比如FOTA包下载。一个扇区4K字节耗时9ms
 * 
 * @param addr     [IN] FLASH中存储数据的地址。
 * @param data     [IN] 要写入FLASH数据的首地址。必须4K字节对齐
 * @param size     [IN] 写入数据的长度.
 * 
 * @attention      由于异常断电会造成flash内容损坏，所以客户必须自行添加头尾校验位来确保内容的有效性。 
 * @warning        使用该接口的前提是能够保证待写入的flash空间已被擦除为全FF，否则会造成脏数据。所以必须与zos_flash_erase接口配套使用，即先擦除一大段flash，再一小段一小段分时写入。
 * 
 * @return ZOS_EOK: 写入成功  ZOS_ELowVbat: 模组电压过低，禁止写入flash
 */
zos_err_t zos_flash_write_no_erase(zos_uint32_t addr,void *data, zos_uint32_t size);

/**
 * @brief   擦除FLASH . 一个扇区4K字节耗时45ms
 * 
 * @param addr     [IN] 需要擦除FLASH中的首地址。
 * @param size     [IN] 需要擦除的长度.
 * 
 * @return ZOS_EOK: 写入成功  ZOS_ELowVbat: 模组电压过低，禁止写入flash
 */
zos_err_t zos_flash_erase(zos_uint32_t addr, zos_uint32_t size);

/**
 * @brief   检查flash地址是否为FTL磨损的flash地址范围
 * 
 * @return ZOS_EOK: 是FTL磨损均衡地址    ZOS_ERROR:不是FTL磨损均衡地址  
 */
zos_err_t zos_flash_is_ftl_addr(zos_uint32_t addr);

/**
 * @brief  磨损均衡的写接口，支持单个参数的修改，其他值不变。一个扇区4K字节耗时58ms
 * 
 * @param addr     [IN]磨损扇区的flash首地址，4K字节对齐
 * @param offset   [IN]待写入的内容偏移，常为结构体某变量在结构体中的偏移
 * @param data     [IN]待写入数据的首地址
 * @param size     [IN]待写入数据的长度
 *
 * @attention   每个4K的flash区域中用户可用的空间为ZOS_FLASH_FTL_AVAILABLE_SIZE，其中头和尾部添加了保护字段。 \n
 *        支持用户按照偏移进行部分读写，以方便结构体具体参数的部分修改。
 * 
 * @return  ZOS_EOK: 写入成功  ZOS_ELowVbat: 模组电压过低，禁止写入flash
 */
zos_err_t zos_flash_ftl_write(zos_uint32_t addr, zos_int32_t offset, zos_uint8_t *data, zos_uint32_t size);

/**
 * @brief  磨损均衡的读接口，支持偏移读取。一个扇区4K字节耗时1.2ms
 * 
 * @param addr     [IN]磨损扇区的flash首地址，4K字节对齐
 * @param data     [IN]待读取的数据存储地址
 * @param size     [IN]待读取数据长度
 * 
 * @attention   每个4K的flash区域中用户可用的空间为ZOS_FLASH_FTL_AVAILABLE_SIZE，其中头和尾部添加了保护字段。 \n
 *    支持用户按照偏移进行部分读写，即addr&0xFFF为地址偏移值。
 * 
 * @return ZOS_EOK: 读成功    ZOS_ERROR:读失败(可能是地址范围不对)
 */
zos_err_t zos_flash_ftl_read(zos_uint32_t addr, zos_uint8_t *data, zos_uint32_t size);



/** 
 * @brief   供用户进行磨损均衡的flash注册
 *
 * @param addr   必须为4K字节对齐的，即尾部必须为0X000。
 * @param addr   必须为4K的整数倍，即必须是整的sector，一个sector为4K字节。
 * 
 * @attention    凡是使用该接口进行磨损和容错机制的，用户可使用的空间大小皆为ZOS_FLASH_FTL_AVAILABLE_SIZE，其中头和尾部添加了保护字段。 \n
 *           用户根据写flash的频繁度，决定size的大小，若size=ZOS_FLASH_SECTOR_LENGTH，则代表放弃磨损均衡，仅使用骑士的头尾保护机制，以解决异常断电的flash容错。 \n
 *           客户完全可以自行设计磨损和内容保护机制，可以调用zos_flash_read和zos_flash_write接口。 \n
 *           目前QS-100模组的flash寿命为10万次，当写频率小于一小时，必须考虑磨损机制，否则无法达到10年使用期限。
 */
void zos_flash_regist_ftl_req(zos_uint32_t addr, zos_uint32_t size);

#endif
